﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using NigLib;
using System.Diagnostics;

namespace ColorPicker
{
    public partial class Main : Form
    {
        DataView dv1, dv2;
        Point mousePosition;
        Point originPosition;
        Bitmap topBmp;
        Bitmap bottomBmp;
        int hMouseHook = 0;
        int hKeyBDHook = 0;
        HookProc mouseHookProc;
        HookProc keyBDHookProc;
        FrmCloseUp frm;
        PickerState state;

        public Main()
        {
            InitializeComponent();

            DataTable dt1 = new DataTable();
            DataTable dt2 = new DataTable();

            dt1.Columns.Add("Red");
            dt1.Columns.Add("Green");
            dt1.Columns.Add("Blue");
            dt1.Columns.Add("Value");

            dt2.Columns.Add("C1");
            dt2.Columns.Add("C2");
            dt2.Columns.Add("C3");
            dt2.Columns.Add("C4");
            dt2.Columns.Add("C5");
            dt2.Columns.Add("C6");
            dt2.Columns.Add("Value");
            dt2.Columns.Add("Position");

            dv1 = new DataView(dt1);
            dv2 = new DataView(dt2);

            dv1.Sort = "Value";
            dv2.Sort = "Value";

            dgv1.DataSource = dv1;
            dgv2.DataSource = dv2;
        }

        private int KeyBDHookProcedure(int nCode, Int32 wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                switch ((WinMessage)wParam)
                {
                    case WinMessage.WM_KEYDOWN:
                        break;
                    case WinMessage.WM_KEYUP:
                        keyboardKeyUpProc((KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct)));
                        break;
                }
            }
            return WinAPIs.CallNextHookEx(hKeyBDHook, nCode, wParam, lParam);
        }

        private int MouseHookProcedure(int nCode, Int32 wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                switch((WinMessage)wParam)
                {
                    case WinMessage.WM_LBUTTONDBLCLK:
                        break;
                    case WinMessage.WM_LBUTTONDOWN:
                        break;
                    case WinMessage.WM_LBUTTONUP:
                        //mouseLeftButtonUpProc((MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct)));
                        break;
                    case WinMessage.WM_MOUSEMOVE:
                        mouseMoveProc((MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct)));
                        break;
                    case WinMessage.WM_RBUTTONDBLCLK:
                        break;
                    case WinMessage.WM_RBUTTONDOWN:
                        break;
                    case WinMessage.WM_RBUTTONUP:
                        break;
                }
            }
            return WinAPIs.CallNextHookEx(hMouseHook, nCode, wParam, lParam);
        }
        private void mouseLeftButtonUpProc(MouseHookStruct mouseHookStruct)
        {
        }

        private void mouseMoveProc(MouseHookStruct mouseHookStruct)
        {
            lblPosition.Text = String.Format("相对坐标:{0} , {1}", mouseHookStruct.Location.X - originPosition.X, mouseHookStruct.Location.Y - originPosition.Y);
            if (state != PickerState.Locating)
                return;
            int a = 31;
            Bitmap bmp1 = new Bitmap(a, a);
            Bitmap bmp2 = new Bitmap(frm.Width, frm.Height);
            Graphics gra = Graphics.FromImage(bmp1);
            gra.CopyFromScreen(mouseHookStruct.Location.X - (a - 1) / 2, mouseHookStruct.Location.Y - (a - 1) / 2, 0, 0, bmp1.Size);
            gra.DrawLines(new Pen(Color.Red), new Point[] { new Point((a - 5) / 2, (a - 1) / 2), new Point((a - 3) / 2, (a - 1) / 2) });
            gra.DrawLines(new Pen(Color.Red), new Point[] { new Point((a + 1) / 2, (a - 1) / 2), new Point((a + 3) / 2, (a - 1) / 2) });
            gra.DrawLines(new Pen(Color.Red), new Point[] { new Point((a - 1) / 2, (a - 5) / 2), new Point((a - 1) / 2, (a - 3) / 2) });
            gra.DrawLines(new Pen(Color.Red), new Point[] { new Point((a - 1) / 2, (a + 1) / 2), new Point((a - 1) / 2, (a + 3) / 2) });
            Graphics gra2 = Graphics.FromImage(bmp2);
            gra2.DrawImage(bmp1, new Rectangle(0, 0, bmp2.Width, bmp2.Height), new Rectangle(0, 0, bmp1.Width, bmp1.Height), GraphicsUnit.Pixel);
            frm.Img = bmp2;
            frm.MouseLocation = new Point(mouseHookStruct.Location.X, mouseHookStruct.Location.Y);
            frm.Location = new Point(mouseHookStruct.Location.X - frm.Width - 20, mouseHookStruct.Location.Y - frm.Height - 20);
            mousePosition = new Point(mouseHookStruct.Location.X, mouseHookStruct.Location.Y);
        }

        private void keyboardKeyUpProc(KeyboardHookStruct keyboardHookStruct)
        {
            if ((Keys)keyboardHookStruct.vkCode != Keys.Enter || state != PickerState.Locating)
                return;
            originPosition = new Point(mousePosition.X, mousePosition.Y);
            lblOrigin.Text = String.Format("鼠标原点:{0} , {1}", originPosition.X, originPosition.Y);
            frm.OriginalPoint = mousePosition;
            frm.Hide();
            chkLocate.Checked = false;
            state = PickerState.Normal;
            topBmp = null;
            bottomBmp = null;
        }

        private void delay(int ms)
        {
            int ticks = WinAPIs.GetTickCount();
            while (ticks + ms > WinAPIs.GetTickCount()) { }
        }

        private void Main_FormClosed(object sender, FormClosedEventArgs e)
        {
            unhook();
        }

        private void unhook()
        {
            if (hMouseHook != 0)
                WinAPIs.UnhookWindowsHookEx(hMouseHook);
            if (hKeyBDHook != 0)
                WinAPIs.UnhookWindowsHookEx(hKeyBDHook);
            mouseHookProc = null;
            keyBDHookProc = null;
            hMouseHook = 0;
            hKeyBDHook = 0;
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }

        private void hook()
        {
            keyBDHookProc = new HookProc(KeyBDHookProcedure);
            mouseHookProc = new HookProc(MouseHookProcedure);
            hMouseHook = WinAPIs.SetWindowsHookEx(
                HookType.WH_MOUSE_LL,
                mouseHookProc,
                WinAPIs.GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName),
                0);
            hKeyBDHook = WinAPIs.SetWindowsHookEx(
                HookType.WH_KEYBOARD_LL,
                keyBDHookProc,
                WinAPIs.GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName),
                0);
        }

        private void btnAnalyze_Click(object sender, EventArgs e)
        {
            try
            {
                DataView dv = dv2.Table.Clone().DefaultView;
                Bitmap bmp = new Bitmap(pbScreenShot.Image);
                for (int x = 0; x < bmp.Width; x++)
                {
                    for (int y = 0; y < bmp.Height; y++)
                    {
                        Color color = bmp.GetPixel(x, y);
                        for (int i = 0; i < dv1.Count; i++)
                        {
                            if (color.R == Convert.ToByte(dv1[i]["Red"])
                                && color.G == Convert.ToByte(dv1[i]["Green"])
                                && color.B == Convert.ToByte(dv1[i]["Blue"]))
                            {
                                DataRow dr = dv.Table.NewRow();
                                dr["C1"] = String.Format("#{0:X}", ((color.R << 16) | (color.G << 8) | (color.B)));
                                dr["Position"] = String.Format("X:{0};Y:{1}", x, y);
                                dr["Value"] = dv1[i]["Value"];
                                dv.Table.Rows.Add(dr);
                                break;
                            }
                        }
                    }
                }
                dv.Sort = "Value DESC";
                for (int i = 0; i < dv.Count && i < 10; i++)
                {
                    dv2.Table.ImportRow(dv.Table.Rows[i]);
                }
                dv2.Table.AcceptChanges();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            

        }

        private void Main_Load(object sender, EventArgs e)
        {
            state = PickerState.Normal;
            hook();
            frm = new FrmCloseUp();
        }

        private void chkLocate_CheckedChanged(object sender, EventArgs e)
        {
            if (chkLocate.Checked)
            {
                frm.Show();
                state = PickerState.Locating;
            }
        }

        private void btnTop_Click(object sender, EventArgs e)
        {
            topBmp = new Bitmap(256, 128);
            Graphics gra = Graphics.FromImage(topBmp);
            gra.CopyFromScreen(mousePosition.X, mousePosition.Y, 0, 0, topBmp.Size);
            if (bottomBmp != null)
            {
                Bitmap bmp = new Bitmap(256, 256);
                Graphics gra1 = Graphics.FromImage(bmp);
                gra1.DrawImage(topBmp, new Point(0, 0));
                gra1.DrawImage(bottomBmp, new Point(0, 128));
                pbScreenShot.Image = bmp;
                gra1.Dispose();
            }
            state = PickerState.Normal;
        }

        private void btnBottom_Click(object sender, EventArgs e)
        {
            bottomBmp = new Bitmap(256, 128);
            Graphics gra = Graphics.FromImage(bottomBmp);
            gra.CopyFromScreen(mousePosition.X, mousePosition.Y + 128, 0, 0, bottomBmp.Size);
            if (topBmp != null)
            {
                Bitmap bmp = new Bitmap(256, 256);
                Graphics gra1 = Graphics.FromImage(bmp);
                gra1.DrawImage(topBmp, new Point(0, 0));
                gra1.DrawImage(bottomBmp, new Point(0, 128));
                pbScreenShot.Image = bmp;
                gra1.Dispose();
            }
            state = PickerState.Normal;
        }
    }

    enum PickerState
    {
        Normal,
        Locating,
        CopyTop,
        CopyBottom,
    }
}
